# -*- coding: utf-8 -*-
"""
车辆连接管理器模块
负责处理车辆连接相关的所有逻辑
"""

from PySide2.QtWidgets import QMessageBox
from PySide2.QtCore import QObject, Signal, Qt, QTimer
from gglobal import logger
from ..threadcore.clientcar_thread import ClientCarThread
from ..threadcore.check_car_connect import CheckCarConnectThread
from .connection_manager import ConnectionStateManager
from .language_manager import LanguageManager


class VehicleConnectionManager(QObject):
    """车辆连接管理器类"""
    
    # 定义信号 - 只保留核心连接管理信号
    connection_status_changed = Signal(bool, str)  # 连接状态, 消息
    command_output = Signal(str)  # 命令输出
    
    def __init__(self, parent=None):
        super().__init__(parent)
        self.parent_widget = parent
        
        # 初始化组件
        self.language_manager = LanguageManager()
        self._connection_manager = ConnectionStateManager(self)
        self._client_car_thread = None
        
        # 连接持有者集合：用于引用计数/租约机制（避免误断开）
        # 说明：当至少有一个持有者时，不执行强制断开；当集合为空时才允许断开。
        self._owners = set()
        
        # UI组件引用（由主界面传入）
        self.connect_button = None
        self.status_bar = None
        
        # 连接状态检测线程（替代定时器，避免阻塞UI）
        self._connection_check_thread = None
        
        # 记录最后连接的IP地址，用于重连
        self._last_connected_ip = None
        
        # 断开流程状态标志：用于规避 release() 自动断开的竞态问题
        # 当为 True 时表示正在执行断开流程，release 不应触发自动断开
        self._is_disconnecting = False
        
    def set_ui_components(self, connect_button, status_bar):
        """设置UI组件引用"""
        self.connect_button = connect_button
        self.status_bar = status_bar
        
        # 连接按钮信号
        self.connect_button.clicked.connect(self.on_connect_clicked)
        
    def on_connect_clicked(self):
        """连接按钮点击处理"""
        logger.info("连接按钮被点击")
        
        if not self.connect_button:
            return
            
        if self.connect_button.is_in_state('connect'):
            # 开始连接 - 需要从主界面获取IP地址
            logger.info("开始连接车辆")
            # 由于这个方法现在直接处理按钮点击，需要获取IP地址
            if hasattr(self.parent_widget, 'ip_combo'):
                ip_text = self.parent_widget.ip_combo.currentText().strip()
                # 提取IP地址（去除设备名称部分）
                if '(' in ip_text and ')' in ip_text:
                    ip_address = ip_text.split('(')[0].strip()
                else:
                    ip_address = ip_text
                logger.info(f"尝试连接到IP: {ip_address}")
                self.connect_to_vehicle(ip_address)
            else:
                logger.warning("无法获取IP地址，请确保UI组件已正确初始化")
        elif self.connect_button.is_in_state('disconnect'):
            # 断开连接
            logger.info("开始断开车辆连接")
            self.disconnect_from_vehicle()
            logger.info("断开连接")
        elif self.connect_button.is_in_state('connecting'):
            # 如果正在连接中，点击按钮应该取消连接
            logger.info("取消车辆连接")
            if self._client_car_thread:
                self._cleanup_client_thread(self._client_car_thread)
            self.connect_button.disconnected()
            cancel_msg = self.language_manager.get_constant('connection_cancelled', '连接已取消')
            if self.status_bar:
                self.status_bar.showMessage(cancel_msg)
            logger.info("用户取消连接")
            
    def connect_to_vehicle(self, ip_address):
        """连接到车辆
        
        参数:
            ip_address: 车辆IP地址
        """
        if not ip_address:
            warning_title = self.language_manager.get_text("warning_title", "警告")
            warning_msg = self.language_manager.get_text("invalid_ip_warning", "请先选择或输入有效的IP地址")
            QMessageBox.warning(self.parent_widget, warning_title, warning_msg)
            return False
            
        # 最终验证IP地址格式
        import re
        ip_pattern = r'^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$'
        if not re.match(ip_pattern, ip_address):
            warning_title = self.language_manager.get_text("warning_title", "警告")
            warning_msg = self.language_manager.get_text("ip_format_warning", "请输入正确的IP地址格式（例如：192.168.1.100）")
            QMessageBox.warning(self.parent_widget, warning_title, warning_msg)
            return False
            
        # 清理之前的连接线程
        if self._client_car_thread:
            self._cleanup_client_thread(self._client_car_thread)
            
        if self.connect_button:
            self.connect_button.start_connect()
        
        # 记录IP地址用于重连
        self._last_connected_ip = ip_address
        
        # 创建并启动车辆连接线程
        self._client_car_thread = ClientCarThread(ip_address, self.parent_widget)
        
        # 只连接核心状态信号，文件操作相关信号由FileManager直接处理
        self._client_car_thread.connection_status.connect(self.on_connection_status_changed)
        self._client_car_thread.command_output.connect(self.on_command_output)
        
        self._client_car_thread.start()
        
        logger.info(f"开始连接到: {ip_address}")
        return True
        
    def disconnect_from_vehicle(self, *, is_manual=True):
        """断开与车辆的连接
        
        参数：
            is_manual: 是否为手动断开（影响状态消息），默认 True。
        """
        # 标记进入断开流程，避免 release() 的自动断开与本流程产生竞态
        self._is_disconnecting = True
        # 清空持有者集合，避免强制断开后遗留无效持有者引用
        try:
            if hasattr(self, '_owners'):
                self._owners.clear()
        except Exception:
            pass
        # 停止连接状态检测线程
        self._stop_connection_check_thread()
        
        # 保存线程引用，避免在操作过程中被其他地方修改
        thread_ref = self._client_car_thread
        
        if thread_ref and hasattr(thread_ref, 'disconnect'):
            try:
                # 调用线程的断开方法
                # 传递断开类型，确保自动断开不会显示“手动断开连接”
                thread_ref.disconnect(is_manual=is_manual)
                
                # 确保线程对象仍然有效且有quit方法后再调用quit
                if thread_ref and hasattr(thread_ref, 'quit'):
                    thread_ref.quit()
                    
                    # 使用统一的清理方法
                    self._cleanup_client_thread(thread_ref)
                else:
                    self._client_car_thread = None
                    
            except AttributeError as e:
                logger.warning(f"断开连接时属性错误: {e}")
                self._client_car_thread = None
            except Exception as e:
                logger.warning(f"断开连接时发生异常: {e}")
                self._client_car_thread = None
        elif self._client_car_thread:
            # 如果线程对象存在但没有disconnect方法，直接清理
            logger.warning("线程对象缺少disconnect方法，直接清理")
            self._client_car_thread = None
        
        # 更新UI状态
        if self.connect_button:
            self.connect_button.disconnected()
        # 使用连接状态管理器更新状态消息（与线程断开保持一致）
        # 若已由线程执行断开并更新状态，这里避免重复设置以减少日志噪音
        if not (locals().get('thread_ref') and hasattr(locals().get('thread_ref'), 'disconnect')):
            self._connection_manager.disconnect(is_manual=is_manual)
        
        # 退出断开流程标志（异常已在内部 try/except 捕获，不会中断流程）
        self._is_disconnecting = False
        
    def _cleanup_client_thread(self, thread):
        """统一的线程清理方法，避免重复的finished信号连接"""
        if not thread:
            self._client_car_thread = None
            return
            
        try:
            # 断开所有可能的信号连接，避免重复连接
            thread.blockSignals(True)
            
            if hasattr(thread, 'quit'):
                thread.quit()
                
            # 只在线程仍在运行时连接finished信号
            if hasattr(thread, 'isRunning') and thread.isRunning():
                # 使用单次连接，避免重复
                thread.finished.connect(
                    lambda: setattr(self, '_client_car_thread', None),
                    Qt.UniqueConnection
                )
            else:
                self._client_car_thread = None
                
        except Exception as e:
            logger.warning(f"清理线程时发生异常: {e}")
            self._client_car_thread = None
            
    def on_connection_status_changed(self, is_connected, message):
        """连接状态变化处理"""
        logger.info(f"收到连接状态变化信号: connected={is_connected}, message={message}")
        
        if is_connected:
            if self.connect_button:
                self.connect_button.connected()
            # 更新状态栏显示连接成功，从ClientCarThread获取IP
            if self._client_car_thread and self.status_bar:
                success_msg = f"{self.language_manager.get_constant('connection_success')}: {self._client_car_thread.ip}"
                self.status_bar.showMessage(success_msg)
                logger.info(f"连接成功: {self._client_car_thread.ip}")
            else:
                success_msg = self.language_manager.get_constant('connection_success')
                if self.status_bar:
                    self.status_bar.showMessage(success_msg)
                logger.info("连接成功")
            
            # 启动连接状态检测线程（每5秒检测一次）
            self._start_connection_check_thread()
            
        else:
            # 停止连接状态检测线程
            self._stop_connection_check_thread()
            
            # 确保连接按钮状态正确重置
            if self.connect_button:
                self.connect_button.disconnected()
            # 强制更新状态栏显示连接失败或断开信息
            if self.status_bar:
                self.status_bar.clearMessage()  # 先清空状态栏
                self.status_bar.showMessage(message)  # 再显示新消息
                # 强制刷新状态栏显示
                self.status_bar.repaint()
            
            # if "连接已断开" not in message:
            #     # 连接失败时显示警告对话框
            #     warning_title = self.language_manager.get_text("warning_title", "警告")
            #     QMessageBox.warning(self.parent_widget, warning_title, message)
            logger.info(f"连接状态变化: {message}")
            
            # 清理连接线程
            if self._client_car_thread:
                self._cleanup_client_thread(self._client_car_thread)
                
        # 转发信号
        self.connection_status_changed.emit(is_connected, message)
        
        # 连接成功后，在信号转发完成后再执行目录操作
        # 这样确保file_manager已经设置好client_thread并连接了信号
        if is_connected and self._client_car_thread:
            # 连接成功后先切换到默认目录，然后获取文件列表
            self._client_car_thread.change_directory(self._client_car_thread.ssh_remote_folder)
            self._client_car_thread.list_directory()
    
    def on_command_output(self, output):
        """命令输出处理"""
        logger.info(f"命令输出: {output}")
        # 转发信号
        self.command_output.emit(output)
    
    def _start_connection_check_thread(self):
        """启动连接状态检测线程"""
        try:
            # 如果已有检测线程在运行，先停止它
            self._stop_connection_check_thread()
            
            # 创建新的连接检测线程
            self._connection_check_thread = CheckCarConnectThread(
                client_car_thread=self._client_car_thread,
                check_interval=5  # 每5秒检测一次
            )
            
            # 连接信号
            self._connection_check_thread.connection_status_checked.connect(
                self._on_connection_status_checked
            )
            
            # 启动线程
            self._connection_check_thread.start()
            logger.info("连接状态检测线程已启动，每5秒检测一次连接状态")
            
        except Exception as e:
            logger.error(f"启动连接状态检测线程时发生错误: {e}")
    
    def _stop_connection_check_thread(self):
        """停止连接状态检测线程"""
        if self._connection_check_thread and self._connection_check_thread.isRunning():
            try:
                # 请求停止线程
                self._connection_check_thread.stop_checking()
                
                # 等待线程结束（最多等待3秒）
                if self._connection_check_thread.wait(3000):
                    logger.info("连接状态检测线程已正常停止")
                else:
                    logger.warning("连接状态检测线程停止超时，强制终止")
                    self._connection_check_thread.terminate()
                    self._connection_check_thread.wait(1000)
                    
            except Exception as e:
                logger.error(f"停止连接状态检测线程时发生错误: {e}")
            finally:
                self._connection_check_thread = None
        elif self._connection_check_thread:
            # 线程已停止，清理引用
            self._connection_check_thread = None
            logger.info("连接状态检测线程已停止")
    
    def _on_connection_status_checked(self, is_alive, message):
        """处理连接状态检测结果（在主线程中运行）"""
        if not is_alive:
            logger.warning(f"检测到连接已断开，停止检测线程并更新连接状态: {message}")
            # 停止检测线程
            self._stop_connection_check_thread()
            # 统一走状态处理逻辑，确保按钮与状态栏正确更新
            # 注意：该方法内部会再次调用停止检测线程，但为幂等操作，安全无副作用
            self.on_connection_status_changed(False, message)
        else:
            logger.debug(f"连接状态正常: {message}")
        
    def get_client_thread(self):
        """获取客户端线程对象"""
        return self._client_car_thread
        
    def is_connected(self):
        """检查是否已连接到车辆"""
        try:
            logger.debug(f"[VehicleConnectionManager] 检查连接状态...")
            
            # 检查线程是否存在
            logger.debug(f"[VehicleConnectionManager] _client_car_thread 存在: {self._client_car_thread is not None}")
            if not self._client_car_thread:
                logger.debug(f"[VehicleConnectionManager] 线程不存在，返回 False")
                return False
            
            # 检查SSH客户端是否存在
            ssh_client = getattr(self._client_car_thread, 'ssh_client', None)
            logger.debug(f"[VehicleConnectionManager] ssh_client 存在: {ssh_client is not None}")
            if not ssh_client:
                logger.debug(f"[VehicleConnectionManager] SSH客户端不存在，返回 False")
                return False
            
            # 直接检查连接是否活跃，不依赖线程运行状态
            # 因为ClientCarThread的run方法执行完连接后就会结束，但连接仍然活跃
            is_alive = ssh_client.is_connection_alive()
            logger.debug(f"[VehicleConnectionManager] ssh_client.is_connection_alive(): {is_alive}")
            return is_alive
            
        except Exception as e:
            logger.error(f"[VehicleConnectionManager] 检查连接状态时发生异常: {e}")
            return False
                
    def get_connection_ip(self):
        """获取当前连接的IP地址"""
        if self._client_car_thread and hasattr(self._client_car_thread, 'ip'):
            return self._client_car_thread.ip
        return None
        
    def execute_command(self, command):
        """执行远程命令"""
        if self._client_car_thread and hasattr(self._client_car_thread, 'execute_command'):
            return self._client_car_thread.execute_command(command)
        return None
        
    def list_directory(self, path):
        """列出目录内容"""
        if self._client_car_thread and hasattr(self._client_car_thread, 'list_directory'):
            self._client_car_thread.list_directory(path)
            
    def get_remote_folder(self):
        """获取远程文件夹路径"""
        if self._client_car_thread and hasattr(self._client_car_thread, 'ssh_remote_folder'):
            return self._client_car_thread.ssh_remote_folder
        return None

    # ------------------ 安全连接持有者管理（新增） ------------------
    def acquire(self, owner):
        """登记连接持有者
        
        参数：
            owner: 任意可哈希对象（窗口、线程等），作为持有者标识
        行为：
            - 将持有者加入集合；
            - 不改变连接状态，仅用于避免误断开。
        """
        try:
            if owner is None:
                return
            self._owners.add(owner)
            logger.info(f"[VehicleConnectionManager] 已登记连接持有者: {owner!r}，当前持有者数量: {len(self._owners)}")
        except Exception as e:
            logger.warning(f"登记连接持有者失败: {e}")

    def release(self, owner):
        """释放连接持有者
        
        参数：
            owner: 之前登记的持有者
        行为：
            - 将持有者从集合移除；
            - 若集合为空且当前处于已连接状态，则执行安全断开。
        """
        try:
            if owner is None:
                return
            if owner in self._owners:
                self._owners.remove(owner)
                logger.info(f"[VehicleConnectionManager] 已释放连接持有者: {owner!r}，剩余持有者数量: {len(self._owners)}")
            else:
                logger.debug(f"[VehicleConnectionManager] 释放持有者时未找到: {owner!r}")

            # 当无持有者且连接仍然存在时，执行安全断开，避免资源泄漏
            if not self._owners:
                # 若正在断开流程中，跳过自动断开以避免重复触发与日志混淆
                if getattr(self, '_is_disconnecting', False):
                    logger.debug("[VehicleConnectionManager] 正在断开流程中，跳过release的自动断开")
                    return
                # 使用 ConnectionStateManager 的状态判断更稳妥
                if getattr(self._connection_manager, 'is_connected', False):
                    logger.info("[VehicleConnectionManager] 无持有者且仍处于连接状态，执行安全断开（自动）")
                    # 这里使用自动断开，避免误显示“手动断开连接”
                    self.disconnect_from_vehicle(is_manual=False)
        except Exception as e:
            logger.warning(f"释放连接持有者失败: {e}")